﻿using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     defined 表达式，可以带括号 (defined(MACRO))或不到括号 (defined MACRO)
/// </summary>
public class DefinedExpression : PreExpression
{
    private readonly SourceNode _definedKeywordToken;
    private SourceNode? _innerLeftParenthesisToken;
    private SourceNode? _innerRightParenthesisToken;
    private SourceNode _macroNameNode;

    internal DefinedExpression(SourceNode? parent, SourceNode definedKeywordToken, SourceNode macroName) :
        base(parent, SyntaxKinds.PreDefinedExpression)
    {
        SetChildField(ref _definedKeywordToken, definedKeywordToken);
        SetChildField(ref _macroNameNode, macroName);
    }

    internal DefinedExpression(SourceNode? parent, SourceNode definedKeywordToken) :
        base(parent, SyntaxKinds.PreDefinedExpression)
    {
        SetChildField(ref _definedKeywordToken, definedKeywordToken);
        _macroNameNode = Default;
    }

    public SourceNode DefinedKeywordToken => _definedKeywordToken;

    public SourceNode MacroNameNode => _macroNameNode;

    public SourceNode? InnerLeftParenthesisToken => _innerLeftParenthesisToken;

    public SourceNode? InnerRightParenthesisToken => _innerRightParenthesisToken;


    public DefinedExpression Update(SourceNode macroNameNode, SourceNode? leftParenthesisToken,
        SourceNode? rightParenthesisToken)
    {
        Debug.Assert(macroNameNode.IsNode(SyntaxKinds.Identifier));
        Debug.Assert(leftParenthesisToken == null || leftParenthesisToken.IsNode(SyntaxKinds.LeftParenthesisToken));
        Debug.Assert(rightParenthesisToken == null ||
                     rightParenthesisToken.IsNode(SyntaxKinds.RightParenthesisToken));
        SetChildField(ref _macroNameNode, IsNullOrDefault, macroNameNode);
        SetChildNullableField(ref _innerLeftParenthesisToken, IsNullOrDefault, leftParenthesisToken);
        SetChildNullableField(ref _innerRightParenthesisToken, IsNullOrDefault, rightParenthesisToken);
        return this;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, DefinedKeywordToken,
            LeftParenthesisToken,
            MacroNameNode,
            RightParenthesisToken);
    }
}

public static partial class NodeFactory
{
    public static DefinedExpression CreateDefinedExpression(SourceNode? parent, SourceNode definedKeywordToken,
        SourceNode macroName)
    {
        Debug.Assert(definedKeywordToken.IsNode(SyntaxKinds.PreDefinedKeywordToken));
        Debug.Assert(macroName.IsNode(SyntaxKinds.Identifier));
        return new DefinedExpression(parent, definedKeywordToken, macroName);
    }

    public static DefinedExpression CreateDefinedExpression(SourceNode? parent, SourceNode definedKeywordToken,
        SourceNode macroName, SourceNode? leftParenthesisToken, SourceNode? rightParenthesisToken)
    {
        Debug.Assert(definedKeywordToken.IsNode(SyntaxKinds.PreDefinedKeywordToken));
        Debug.Assert(macroName.IsNode(SyntaxKinds.Identifier));
        Debug.Assert(leftParenthesisToken == null || leftParenthesisToken.IsNode(SyntaxKinds.LeftParenthesisToken));
        Debug.Assert(rightParenthesisToken == null ||
                     rightParenthesisToken.IsNode(SyntaxKinds.RightParenthesisToken));
        DefinedExpression expr = new(parent, definedKeywordToken);
        return expr.Update(macroName, leftParenthesisToken, rightParenthesisToken);
    }
}